package com.hzsk.lisence.config;

import com.alibaba.fastjson.JSON;
import com.hzsk.lisence.config.myexception.OperateException;
import com.hzsk.lisence.entity.LisenceLogEntity;
import com.hzsk.lisence.service.LicenseLogSysService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class SysLogAspect {

    private static final String CLASS_NAME = "calssName";//类名称
    private static final String CLASS_METHOD = "calssMethod";//类方法名称

    @Autowired
    private LicenseLogSysService licenseLogSysService;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation(com.hzsk.lisence.config.AnnotationForLog)")
    public void logPoinCut() {
    }

    @Around("logPoinCut()")
    public Object doAroundAdvice(ProceedingJoinPoint joinPoint) throws OperateException {
        String classType = joinPoint.getTarget().getClass().getName();//获取类名  //Class<?> clazz = Class.forName(classType);//转成类对象
        LisenceLogEntity lrpLogSys = new LisenceLogEntity();
        Map<String,Object> map = new HashMap<String,Object>();//存放数据参数
        map.put(CLASS_NAME,classType);//TODO map中放入类名称
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//从切面织入点处通过反射机制获取织入点处的方法
        Method method = signature.getMethod();//获取切入点所在的方法
        map.put(CLASS_METHOD,method.getName()); //TODO map中放入类方法名称

        AnnotationForLog annotationForLog = method.getAnnotation(AnnotationForLog.class);
        Object[] args = joinPoint.getArgs();// 请求的方法参数值
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();// 请求的方法参数名称
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            Map<String,Object> dateMap = new HashMap<String,Object>();//存放请求方法数据参数及参数值
            for (int i = 0; i < args.length; i++) {
                dateMap.put(paramNames[i],args[i]);//TODO 请求参数名称 和  该参数对应的值
                if (paramNames[i].equals("userId")) lrpLogSys.setInsertUser((Integer) args[i]);
            }
            map.put("dateMap",dateMap); //TODO map中放入类方法名称
        }
        if (annotationForLog != null) {
            lrpLogSys = doLrpLogSys(annotationForLog,lrpLogSys);
            String jsonString = JSON.toJSONString(map);
            if (jsonString.length() > 1024 ) jsonString = "数据过长不做展示";
            lrpLogSys.setDescription(jsonString);//获取的操作描述json数据
        }

        Object obj = null;
        try {//正常日志处理
            obj = joinPoint.proceed(); //可以加参数
            lrpLogSys.setSuccessOrNot(1);
            licenseLogSysService.save(lrpLogSys);
            return obj;
        } catch (Throwable throwable) {//异常日志处理
            lrpLogSys.setWhyError(throwable.getMessage());
            lrpLogSys.setSuccessOrNot(0);
            licenseLogSysService.save(lrpLogSys);
            throwable.printStackTrace();
            throw new OperateException(throwable.toString());
        }
    }

    /**
     * 封装成日志插入数据
     * [annotationForLog, lrpLogSys]
     * @throws
     * @author wu yu xin
     * @date 2024/05/27 16:33
     */
    public LisenceLogEntity doLrpLogSys(AnnotationForLog annotationForLog,LisenceLogEntity lrpLogSys){
        String operationType = annotationForLog.operationType().name();//操作类型 ADD,EDIT,DEL,QUERY
        String operation = annotationForLog.operation();//白话描述
        String operationalEntity = annotationForLog.operationalEntity();//操作的是那个实体 Student.java%STUDENT_T%展示名称%主键
        lrpLogSys.setOperationType(operationType);//获取的操作
        lrpLogSys.setOperation(operation);//获取的操作描述
        lrpLogSys.setOperationalEntity(operationalEntity);//对那个实体进行操作
        return lrpLogSys;

    }


}